/*
 * MainView.java
 *
 * Created on __DATE__, __TIME__
 */

import irnode.IRNode;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;


import symbol.ClassTable;
import symbol.Curr;
import util.ErrorMsg;

import xyz.SimpleNode;
import xyz.XYZLexer;
import xyz.XYZParser;

/**
 *
 * @author  hupan
 */
public class XYZCompiler extends javax.swing.JFrame {

	/** Creates new form MainView */
	public XYZCompiler() {
		initComponents();
	}

	/** This method is called from within the constructor to
	 * initialize the form.
	 * WARNING: Do NOT modify this code. The content of this method is
	 * always regenerated by the Form Editor.
	 */
	//GEN-BEGIN:initComponents
	// <editor-fold defaultstate="collapsed" desc="Generated Code">
	private void initComponents() {
		
		headerView = new MyRowHeaderView();
		lineNumShown = true;
		ifSaved = false;
		filename = null;
		inputPanel = new javax.swing.JPanel();
		inputScrollPanel = new javax.swing.JScrollPane();
		inputScrollPanel.setRowHeaderView(headerView);
		inputTextPane = new javax.swing.JTextPane();
		consolePanel = new javax.swing.JPanel();
		consoleScrollPanel = new javax.swing.JScrollPane();
		consoleTextPane = new javax.swing.JTextPane();
//		consoleTextArea.setLineWrap(true);
		output = new javax.swing.JPanel();
		outPutPane = new javax.swing.JTabbedPane();
		parsertreeScrollPane = new javax.swing.JScrollPane();
		parserIRTreeScrollPane = new javax.swing.JScrollPane();
		parserTree = null;
		parserIRTree = null;
		mainMenuBar = new javax.swing.JMenuBar();
		menuFile = new javax.swing.JMenu();
		buttonOpenFile = new javax.swing.JMenuItem();
		buttonSaveFile = new javax.swing.JMenuItem();
		menuOption = new javax.swing.JMenu();
		buttonLexical = new javax.swing.JMenuItem();
		buttonParsing = new javax.swing.JMenuItem();
		buttonSemantic = new javax.swing.JMenuItem();
		buttonExit = new javax.swing.JMenuItem();
		menuView = new javax.swing.JMenu();
		buttonShowLineNum = new javax.swing.JMenuItem();
		attr = new SimpleAttributeSet();
		StyleConstants.setFontSize(attr, 15);

		setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
		setTitle("XYZ Compiler");

		inputPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null,
				"Input"));


		inputTextPane.setCharacterAttributes(attr, false);
		inputScrollPanel.setViewportView(inputTextPane);

		javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(
				inputPanel);
		inputPanel.setLayout(inputPanelLayout);
		inputPanelLayout.setHorizontalGroup(inputPanelLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addGroup(
						inputPanelLayout.createSequentialGroup().addComponent(
								inputScrollPanel,
								javax.swing.GroupLayout.DEFAULT_SIZE, 450,
								Short.MAX_VALUE).addContainerGap()));
		inputPanelLayout.setVerticalGroup(inputPanelLayout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addComponent(
				inputScrollPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 331,
				Short.MAX_VALUE));

		consolePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(
				null, "Console"));

//		consoleTextArea.setColumns(20);
		consoleTextPane.setEditable(false);
//		consoleTextArea.setRows(5);
		consoleScrollPanel.setViewportView(consoleTextPane);

		javax.swing.GroupLayout consolePanelLayout = new javax.swing.GroupLayout(
				consolePanel);
		consolePanel.setLayout(consolePanelLayout);
		consolePanelLayout.setHorizontalGroup(consolePanelLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addComponent(consoleScrollPanel,
						javax.swing.GroupLayout.DEFAULT_SIZE, 1000,
						Short.MAX_VALUE));
		consolePanelLayout.setVerticalGroup(consolePanelLayout
				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
				.addComponent(consoleScrollPanel,
						javax.swing.GroupLayout.DEFAULT_SIZE, 209,
						Short.MAX_VALUE));


		parsertreeScrollPane.setViewportView(parserTree);
		parsertreeScrollPane.setBorder(null);

		outPutPane.addTab("Parser Tree", parsertreeScrollPane);

		parserIRTreeScrollPane.setViewportView(parserIRTree);
		parserIRTreeScrollPane.setBorder(null);

		outPutPane.addTab("IR Tree", parserIRTreeScrollPane);
		
		javax.swing.GroupLayout outputLayout = new javax.swing.GroupLayout(
		output);
		output.setLayout(outputLayout);
		outputLayout.setHorizontalGroup(outputLayout.createParallelGroup(
		javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				outputLayout.createSequentialGroup().addContainerGap(
				javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
			.addComponent(outPutPane,
						javax.swing.GroupLayout.PREFERRED_SIZE, 300,
						javax.swing.GroupLayout.PREFERRED_SIZE)));
		outputLayout.setVerticalGroup(outputLayout.createParallelGroup(
		javax.swing.GroupLayout.Alignment.LEADING).addComponent(
				outPutPane, javax.swing.GroupLayout.DEFAULT_SIZE, 331,
		Short.MAX_VALUE));
		
//		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
//				getContentPane());
//		getContentPane().setLayout(layout);
//		layout.setHorizontalGroup(layout.createParallelGroup(
//				javax.swing.GroupLayout.Alignment.LEADING).addGroup(
//				layout.createSequentialGroup().addGap(340, 340, 340)
//						.addComponent(outPutPane,
//								javax.swing.GroupLayout.PREFERRED_SIZE, 192,
//								javax.swing.GroupLayout.PREFERRED_SIZE)
//						.addContainerGap(20, Short.MAX_VALUE)));
//		layout
//				.setVerticalGroup(layout.createParallelGroup(
//						javax.swing.GroupLayout.Alignment.LEADING).addGroup(
//						layout.createSequentialGroup().addGap(29, 29, 29)
//								.addComponent(outPutPane,
//										javax.swing.GroupLayout.DEFAULT_SIZE,
//										225, Short.MAX_VALUE).addContainerGap(
//										117, Short.MAX_VALUE)));
		
		menuFile.setText("File");

		buttonOpenFile.setText("Open");
		buttonOpenFile.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				buttonOpenFileActionPerformed(evt);
			}
		});
		menuFile.add(buttonOpenFile);

		buttonSaveFile.setText("Save");
		buttonSaveFile.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				buttonSaveFileActionPerformed(evt);
			}
		});
		menuFile.add(buttonSaveFile);

		mainMenuBar.add(menuFile);

		menuOption.setText("Option");

		buttonLexical.setText("Lexical Analysing");
		buttonLexical.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				buttonLexicalActionPerformed(evt);
			}
		});
		menuOption.add(buttonLexical);

		buttonParsing.setText("Start Parsing");
		buttonParsing.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				buttonParsingActionPerformed(evt);
			}
		});
		menuOption.add(buttonParsing);
		
		buttonSemantic.setText("Semantic Analysing");
		buttonSemantic.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(java.awt.event.ActionEvent evt){
				buttonSemanticActionPerformed(evt);
			}
		});
		menuOption.add(buttonSemantic);
		
		/*button3AC.setText("3AC translation");
		button3AC.addActionListener(new java.awt.event.ActionListener(){
			public void actionPerformed(java.awt.event.ActionEvent evt){
				button3ACActionPerformed(evt);
			}
		});
		menuOption.add(button3AC);*/

		buttonExit.setText("Exit");
		buttonExit.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				buttonExitActionPerformed(evt);
			}
		});
		menuOption.add(buttonExit);

		mainMenuBar.add(menuOption);
		
		menuView.setText("View");
		
		buttonShowLineNum.setText("Show Line Number");
		buttonShowLineNum.addActionListener(new java.awt.event.ActionListener() {
			public void actionPerformed(java.awt.event.ActionEvent evt) {
				buttonShowLineNumActionPerformed(evt);
			}
		});
		menuView.add(buttonShowLineNum);
		mainMenuBar.add(menuView);

		setJMenuBar(mainMenuBar);

		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
				getContentPane());
		getContentPane().setLayout(layout);
		layout.setHorizontalGroup(layout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				javax.swing.GroupLayout.Alignment.TRAILING,
				layout.createSequentialGroup().addComponent(inputPanel,
						javax.swing.GroupLayout.DEFAULT_SIZE,
						javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
						.addGap(18, 18, 18).addComponent(output,
								javax.swing.GroupLayout.PREFERRED_SIZE,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								javax.swing.GroupLayout.PREFERRED_SIZE))
				.addComponent(consolePanel,
						javax.swing.GroupLayout.DEFAULT_SIZE,
						javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE));
		layout.setVerticalGroup(layout.createParallelGroup(
				javax.swing.GroupLayout.Alignment.LEADING).addGroup(
				layout.createSequentialGroup().addGroup(
						layout.createParallelGroup(
								javax.swing.GroupLayout.Alignment.LEADING,
								false).addComponent(output,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								Short.MAX_VALUE).addComponent(inputPanel,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								Short.MAX_VALUE)).addPreferredGap(
						javax.swing.LayoutStyle.ComponentPlacement.RELATED)
						.addComponent(consolePanel,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								javax.swing.GroupLayout.DEFAULT_SIZE,
								Short.MAX_VALUE)));

		pack();
	}// </editor-fold>
	//GEN-END:initComponents

	private SimpleNode parseTree(){
		int rvalue = executeLexicalAnalysing();
		if (rvalue == -1) {
			return null;
		} else {
			List<String> msgs = new ArrayList<String>();
			SimpleNode n  = XYZParser.Parse(filename, msgs);
			for (int i = 0; i < msgs.size(); i++){
//				SimpleAttributeSet set = new SimpleAttributeSet();
				Document doc = consoleTextPane.getStyledDocument();
				try {
					doc.insertString(doc.getLength(), msgs.get(i), attr);
				} catch (BadLocationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if(n != null){
				displayTree(n);
			}
			else System.out.println("node is null");
			return n;
		}
		
	}
	
	private void buttonParsingActionPerformed(java.awt.event.ActionEvent evt) {
		parseTree();
	}

	private void displayTree(SimpleNode n){
		DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(n.toString());
	    newNode.setAllowsChildren(true); 
	    cloneTreeNode(n,newNode);
	    parserTree = new JTree(newNode);
	    final ImageIcon fIcon = new ImageIcon("images/f.PNG");
	    final ImageIcon sonIcon = new ImageIcon("images/son.PNG");
	    parserTree.setCellRenderer(new DefaultTreeCellRenderer(){
            public Icon getClosedIcon() {
                return fIcon;                                                                                                                                   
            }
            public Icon getLeafIcon(){
            	return sonIcon; 
            }
            public Icon getOpenIcon(){
            	return fIcon;
            }
	    });
	    parsertreeScrollPane.setViewportView(parserTree);
	    parsertreeScrollPane.repaint();
	    outPutPane.repaint();
	}
	

	private void displayIRTree(IRNode n){
		DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(n.toString());
	    newNode.setAllowsChildren(true); 
	    cloneIRTreeNode(n,newNode);
	    parserIRTree = new JTree(newNode);
	    final ImageIcon fIcon = new ImageIcon("images/f.PNG");
	    final ImageIcon sonIcon = new ImageIcon("images/son.PNG");
	    parserIRTree.setCellRenderer(new DefaultTreeCellRenderer(){
            public Icon getClosedIcon() {
                return fIcon;                                                                                                                                   
            }
            public Icon getLeafIcon(){
            	return sonIcon; 
            }
            public Icon getOpenIcon(){
            	return fIcon;
            }
	    });
	    parserIRTreeScrollPane.setViewportView(parserIRTree);
	    parserIRTreeScrollPane.repaint();
	    outPutPane.repaint();
	}
	
	private void cloneIRTreeNode(IRNode n, DefaultMutableTreeNode tree){
	    if   (n != null)   { 
	        for   (int   i   =   0;   i   <   n.getNumChildren();   ++i)   { 
	            try   { 
	              DefaultMutableTreeNode   node = new DefaultMutableTreeNode(n.getChild(i).toString()); 
	              tree.add((DefaultMutableTreeNode)node); 
	              cloneIRTreeNode(n.getChild(i),node); 
	            } 
	            catch   (Exception   e)   { 
	                e.printStackTrace(); 
	            } 
	        } 
	    } 
	}
	
	private void cloneTreeNode(SimpleNode n, DefaultMutableTreeNode tree){
	    if   (n != null)   { 
	        for   (int   i   =   0;   i   <   n.jjtGetNumChildren();   ++i)   { 
	            try   { 
	              DefaultMutableTreeNode   node = new DefaultMutableTreeNode(n.jjtGetChild(i).toString()); 
	              tree.add((DefaultMutableTreeNode)node); 
	              cloneTreeNode((SimpleNode)n.jjtGetChild(i),node); 
	            } 
	            catch   (Exception   e)   { 
	                e.printStackTrace(); 
	            } 
	        } 
	    } 
	}
	
	private void buttonLexicalActionPerformed(java.awt.event.ActionEvent evt) {
		// TODO add your handling code here:
		executeLexicalAnalysing();
		
	}
	
	private void buttonShowLineNumActionPerformed(java.awt.event.ActionEvent evt) {
		// TODO add your handling code here:
		if(!lineNumShown){
			inputScrollPanel.setRowHeaderView(headerView);
			lineNumShown = true;
		}
		else{
			inputScrollPanel.setRowHeaderView(null);
			lineNumShown = false;
		}
		return;
	}
	
	private int executeLexicalAnalysing(){

		if(parserTree!=null){
			parserTree = null;
			parsertreeScrollPane.setViewportView(parserTree);
			parsertreeScrollPane.repaint();
		    outPutPane.repaint();
		}
		if(parserIRTree!=null){
			parserIRTree = null;
			parserIRTreeScrollPane.setViewportView(parserIRTree);
			parserIRTreeScrollPane.repaint();
		    outPutPane.repaint();
		}
		consoleTextPane.setText("");
		if(filename == null){
//			SimpleAttributeSet set = new SimpleAttributeSet();
			Document doc = consoleTextPane.getStyledDocument();
			try {
				doc.insertString(doc.getLength(), "Please choose a file first!", attr);
			} catch (BadLocationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return -1;
		}
		if (ifSaved) {
			return startLexicalAnalysing();
		} else {
			int option = JOptionPane.showConfirmDialog(this,
					"Analyse after saving?", "Select an option",
					JOptionPane.YES_NO_OPTION);
			if (option == JOptionPane.YES_OPTION) {
				saveFile();
				return startLexicalAnalysing();
			}
			return -1;
		}
	}
	
	private IRNode executeSemanticAnalysis(){
		SimpleNode n = parseTree();
		
		List<String> semanticErrorMsgs = ErrorMsg.semanticErrorMsgs;
		semanticErrorMsgs.clear();
		
		if(n == null)
			return null;
		ClassTable.ConstructClassTable(n);
		
		for (int i = 0; i < semanticErrorMsgs.size(); i++){
			Document doc = consoleTextPane.getStyledDocument();
			try {
				doc.insertString(doc.getLength(), semanticErrorMsgs.get(i), attr);
			} catch (BadLocationException e) {
				e.printStackTrace();
			}
		}
		
		IRNode programIR = Curr.currNode;
		if(programIR != null){
			displayIRTree(programIR);
		}
		else System.out.println("programIR is null");
		return Curr.currNode;
	}
	
	private void buttonSaveFileActionPerformed(java.awt.event.ActionEvent evt) {
		// TODO add your handling code here:
		saveFile();

	}

	
	private int startLexicalAnalysing() {

		List<String> msgs = new ArrayList<String>();
		int rvalue = XYZLexer.Lex(filename, msgs);
		for (int i = 0; i < msgs.size(); i++){
//			SimpleAttributeSet set = new SimpleAttributeSet();
			Document doc = consoleTextPane.getStyledDocument();
			try {
				doc.insertString(doc.getLength(), msgs.get(i), attr);
			} catch (BadLocationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return rvalue;
	}

	private void saveFile() {
		try {
			FileOutputStream fout = new FileOutputStream(filename);
			fout.write(inputTextPane.getText().getBytes());
			ifSaved = true;
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException es) {
			es.printStackTrace();
		}
	}

	private void buttonExitActionPerformed(java.awt.event.ActionEvent evt) {
		System.exit(0);
	}

	private void buttonSemanticActionPerformed(java.awt.event.ActionEvent evt){
		executeSemanticAnalysis();
	}
	
	private void buttonOpenFileActionPerformed(java.awt.event.ActionEvent evt) {
		// TODO add your handlin
		JFileChooser fc = new JFileChooser();
		int select = fc.showOpenDialog(this);
		if (select == JFileChooser.APPROVE_OPTION) {
			filename = fc.getSelectedFile().getPath();
			try {
				File f = new File(filename);
				FileInputStream fi = new FileInputStream(f);
				byte[] bytes = new byte[(int) f.length()];
				fi.read(bytes);
				String body = new String(bytes);
				inputTextPane.setText(body);
				inputTextPane.repaint();
				ifSaved = true;

				inputTextPane.getDocument().addDocumentListener(
						new DocumentListener() {
							public void insertUpdate(DocumentEvent e) {
								ifSaved = false;
							}

							public void removeUpdate(DocumentEvent e) {
								ifSaved = false;
							}

							public void changedUpdate(DocumentEvent e) {
								ifSaved = false;
							}
						});
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			} catch (IOException es) {
				es.printStackTrace();
			}
		}
	}

	/**
	 * @param args the command line arguments
	 */
	public static void main(String args[]) {
		java.awt.EventQueue.invokeLater(new Runnable() {
			public void run() {
				new XYZCompiler().setVisible(true);
			}
		});
	}

	//GEN-BEGIN:variables
	// Variables declaration - do not modify
	private javax.swing.JMenuItem buttonExit;
	private javax.swing.JMenuItem buttonLexical;
	private javax.swing.JMenuItem buttonOpenFile;
	private javax.swing.JMenuItem buttonParsing;
	private javax.swing.JMenuItem buttonSemantic;
	private javax.swing.JMenuItem buttonSaveFile;
	private javax.swing.JMenuItem buttonShowLineNum;
	private javax.swing.JPanel consolePanel;
	private javax.swing.JScrollPane consoleScrollPanel;
	private javax.swing.JTextPane consoleTextPane;
	private javax.swing.JPanel inputPanel;
	private javax.swing.JScrollPane inputScrollPanel;
	private javax.swing.JTextPane inputTextPane;
	private javax.swing.JMenuBar mainMenuBar;
	private javax.swing.JMenu menuFile;
	private javax.swing.JMenu menuOption;
	private javax.swing.JMenu menuView;
	private javax.swing.JTree parserTree;
	private javax.swing.JTree parserIRTree;
	private javax.swing.JPanel output;
	private javax.swing.JTabbedPane outPutPane;
	private javax.swing.JScrollPane parsertreeScrollPane;
	private javax.swing.JScrollPane parserIRTreeScrollPane;
	private String filename;
	private boolean ifSaved;
	private MutableAttributeSet attr;
	private MyRowHeaderView headerView;
	private boolean lineNumShown;
	// End of variables declaration//GEN-END:variables

}